package com.blog.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.blog.constant.MsgConstant;
import com.blog.mapper.UserMapper;
import com.blog.pojo.dto.UserDTO;
import com.blog.pojo.dto.UserLoginDto;
import com.blog.pojo.entity.User;
import com.blog.service.UserService;
import com.blog.util.ThreadLocalUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.DigestUtils;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
@Transactional(rollbackFor = Exception.class) // 添加事务回滚注解，当遇到错误时，会回滚事务，确保数据的完整
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {

    @Autowired
    private UserMapper userMapper;

    /**
     * 根据用户名查询用户数据
     * @param username
     * @return
     */
    @Override
    @Transactional(readOnly = true)
    public User getByUsername(String username) {
        User user = userMapper.getByUsername(username);
        return user;
    }

    /**
     * 登入
     * @param userLoginDto
     * @return
     */
    @Override
    public User login(UserLoginDto userLoginDto) {
        String password = userLoginDto.getPassword();

        //接收通过用户名查询到的数据
        User user = userMapper.getByUsername(userLoginDto.getUsername());

        //判断数据是否存在，不存在说明用户名错误 或者 没有该用户
        if (user == null) {
            return null;
        }

        //将密码转换成由MD5加密的密码，与返回的用户数据中的密码进行比对
        password = DigestUtils.md5DigestAsHex(password.getBytes());
        if ( !password.equals( user.getPassword() ) ) {//验证不通过，返回空
            return null;
        }
        //所有验证都通过，返回用户数据
        return user;
    }

    /**
     * 注册
     * @param username
     * @param password
     */
    @Override
    public void register(String username, String password) {
        //经过controller的判断，可以直接调用mapper接口进行注册()
        //需要封装成User对象在进行数据插入,密码需要进行MD5加密
        User user = User.builder()
                .username(username)
                .password(DigestUtils.md5DigestAsHex(password.getBytes()))
                .build();
        //对公共字段-时间 进行填充，后续可以统一利用AOP切面填充
        user.setCreateTime(LocalDateTime.now());
        user.setUpdateTime(LocalDateTime.now());

        //数据处理完毕，进行插入
        userMapper.savaUser(user);

    }

    /**
     * 分页查询用户信息
     * @param pageNum
     * @param pageSize
     * @param id
     * @param username
     * @return
     */
    @Override
    @Transactional(readOnly = true)
    public IPage<User> getUserPage(Integer pageNum, Integer pageSize, Long id, String username, Long status) {
        // 1. 创建一个分页对象，设置分页条件
        Page page = new Page<>(pageNum, pageSize);

        // 2. 构建wrapper其他的查询条件
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();

        if (id != null) {
            wrapper.eq(User::getId, id);
        }
        if( StrUtil.isNotBlank(username) ){
            wrapper.like(User::getUsername, username);
        }
        if (status != null) {
            wrapper.eq(User::getStatus, status);
        }

        // 3. 设置查询到的数据按照id升序排序
        wrapper.orderByAsc(User::getId);

        // 4. 执行分页查询，并返回数据
        try {
            return this.page(page, wrapper);
        } catch (Exception e) {
            log.info("分页查询失败：{}", e);
            throw new RuntimeException(MsgConstant.USER_SELECT_ERROR);
        }
    }

    /**
     * 删除单个用户
     * @param id
     */
    @Override
    public void deleteUser(Long id) {
        // 1. 先检查要删除的用户是否存在于数据库中
        if (this.getById(id) == null) {
            throw new RuntimeException(MsgConstant.USER_NO_EXISTS);
        }

        // 2. 进行删除
        try {
            this.removeById(id);
        } catch (Exception e) {
            log.info("单独删除用户失败：{}", e);
            throw new RuntimeException(MsgConstant.USER_DELETE_ERROR);
        }
    }

    /**
     * 批量删除用户
     * @param ids
     */
    @Override
    public void deleteUsers(List<Long> ids) {
        // 1. 先检查要删除的用户是否都存在于数据库中
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(User::getId, ids);
        if (this.count(wrapper) != ids.size()) {
            throw new RuntimeException(MsgConstant.USER_NO_EXISTS);
        }

        // 2. 进行删除
        try {
            this.removeBatchByIds(ids);
        } catch (Exception e) {
            log.error("批量删除用户失败：", e);
            throw new RuntimeException(MsgConstant.USER_DELETE_ERROR);
        }
    }

    /**
     * 修改用户信息
     * @param userDTO
     */
    @Override
    public void updateUserInfo(UserDTO userDTO) {
        // 1. 先检查要修改的用户是否存在于数据库中
        if(this.getById(userDTO.getId()) == null ){ // 如果获取到的为空，证明不存在
            throw new RuntimeException(MsgConstant.USER_NO_EXISTS);
        }

        // 2. 将DTO转成User实体
        User user = BeanUtil.copyProperties(userDTO, User.class);

        user.updateTime();
        // 3. 进行修改
        try {
            this.updateById(user);
        } catch (Exception e) {
            log.info("用户修改失败：{}", e);
            throw new RuntimeException(MsgConstant.USER_UPDATE_ERROR);
        }

    }

    /**
     * 获取用户数量
     * @return
     */
    @Override
    public Long getUserCount() {
        long count = 0;
        try {
            count = this.count();
            return count;
        } catch (Exception e) {
            log.error("获取用户数量失败：", e);
            throw new RuntimeException(MsgConstant.USER_SELECT_ERROR);
        }
    }

    /**
     * 修改用户密码
     * @param newPwd
     */
    @Override
    public void updatePwd(String newPwd) {
        //封装成User对象，调用update方法进行修改
        User user = User.builder()
                .password(DigestUtils.md5DigestAsHex(newPwd.getBytes()))
                .build();
        //设置修改时间
        user.setUpdateTime(LocalDateTime.now());
        //获取id吗，根据id进行修改
        Map<String, Object> map = ThreadLocalUtil.get();

        user.setId((Long) map.get("id"));

        userMapper.update(user);


    }

    /**
     * 修改头像
     * @param avatarUrl
     */
    @Override
    public void updateAvatar(String avatarUrl) {
        Map<String, Object> map = ThreadLocalUtil.get();
        Long id = (Long) map.get("id");
        User user = User.builder()
                .id(id)
                .userAvatar(avatarUrl)
                .updateTime(LocalDateTime.now())
                .build();

        userMapper.update(user);

    }


}
